.TH std::counting_semaphore::acquire 3 "2024.06.10" "http://cppreference.com" "C++ Standard Libary"
.SH NAME
std::counting_semaphore::acquire \- std::counting_semaphore::acquire

.SH Synopsis
   void acquire();  \fI(since C++20)\fP

   Atomically decrements the internal counter by 1 if it is greater than 0; otherwise
   blocks until it is greater than 0 and can successfully decrement the internal
   counter.

.SH Preconditions

   \fI(none)\fP

.SH Parameters

   \fI(none)\fP

.SH Exceptions

   May throw std::system_error.

.SH Example

   The example visualizes a concurrent work of several randomized threads when no more
   than N (N is the semaphore desired value) of the thread-functions are active, while
   the other might wait on the semaphore.


// Run this code

 #include <array>
 #include <chrono>
 #include <cstddef>
 #include <iomanip>
 #include <iostream>
 #include <mutex>
 #include <new>
 #include <random>
 #include <semaphore>
 #include <thread>
 #include <vector>

 using namespace std::literals;

 constexpr std::size_t max_threads{10U}; // change and see the effect
 constexpr std::ptrdiff_t max_sema_threads{3}; // {1} for binary semaphore
 std::counting_semaphore semaphore{max_sema_threads};
 constexpr auto time_tick{10ms};

 unsigned rnd()
 {
     static std::uniform_int_distribution<unsigned> distribution{2U, 9U}; // [delays]
     static std::random_device engine;
     static std::mt19937 noise{engine()};
     return distribution(noise);
 }

 class alignas(std::hardware_destructive_interference_size) Guide
 {
     inline static std::mutex cout_mutex;
     inline static std::chrono::time_point<std::chrono::high_resolution_clock> started_at;
     unsigned delay{rnd()}, occupy{rnd()}, wait_on_sema{};

 public:
     static void start_time() { started_at = std::chrono::high_resolution_clock::now(); }

     void initial_delay() { std::this_thread::sleep_for(delay * time_tick); }

     void occupy_sema()
     {
         wait_on_sema =
             static_cast<unsigned>(std::chrono::duration_cast<std::chrono::milliseconds>(
                 std::chrono::high_resolution_clock::now() - started_at -
                 delay * time_tick).count() / time_tick.count());
         std::this_thread::sleep_for(occupy * time_tick);
     }

     void visualize(unsigned id, unsigned x_scale = 2) const
     {
         auto cout_n = [=](auto str, unsigned n)
         {
             for (n *= x_scale; n-- > 0; std::cout << str)
                 ;
         };
         std::lock_guard lk{cout_mutex};
         std::cout << '#' << std::setw(2) << id << ' ';
         cout_n("░", delay);
         cout_n("▒", wait_on_sema);
         cout_n("█", occupy);
         std::cout << '\\n';
     }

     static void show_info()
     {
         std::cout << "\\nThreads: " << max_threads << ", Throughput: " << max_sema_threads
                   << " │ Legend: initial delay ░░ │ wait state ▒▒ │ sema occupation ██ \\n"
                   << std::endl;
     }
 };

 std::array<Guide, max_threads> guides;

 void workerThread(unsigned id)
 {
     guides[id].initial_delay(); // emulate some work before sema acquisition
     semaphore.acquire();        // wait until a free sema slot is available
     guides[id].occupy_sema();   // emulate some work while sema is acquired
     semaphore.release();
     guides[id].visualize(id);
 }

 int main()
 {
     std::vector<std::jthread> threads;
     threads.reserve(max_threads);

     Guide::show_info();
     Guide::start_time();

     for (auto id{0U}; id != max_threads; ++id)
         threads.push_back(std::jthread(workerThread, id));
 }

.SH Possible output:

 Default case: max_threads{10U}, max_sema_threads{3}

 Threads: 10, Throughput: 3 │ Legend: initial delay ░░ │ wait state ▒▒ │ sema occupation ██

 # 1 ░░░░██████
 # 2 ░░░░████████
 # 5 ░░░░░░██████████
 # 8 ░░░░░░░░░░░░████████████
 # 9 ░░░░░░░░░░░░██████████████
 # 7 ░░░░░░░░░░░░▒▒▒▒████████████████
 # 4 ░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒████████
 # 6 ░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒██████████████████
 # 3 ░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████
 # 0 ░░░░░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██████████████

 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────
 "Enough for everyone" case (no wait states!): max_threads{10U}, max_sema_threads{10}

 Threads: 10, Throughput: 10 │ Legend: initial delay ░░ │ wait state ▒▒ │ sema occupation ██

 # 4 ░░░░██████
 # 5 ░░░░░░████
 # 3 ░░░░██████████
 # 1 ░░░░██████████
 # 8 ░░░░░░░░████████████
 # 6 ░░░░░░░░░░░░░░░░██████
 # 7 ░░░░░░░░░░░░░░░░██████
 # 9 ░░░░░░░░░░░░░░░░██████████
 # 0 ░░░░░░░░░░░░██████████████████
 # 2 ░░░░░░░░░░░░░░░░░░████████████

 ──────────────────────────────────────────────────────────────────────────────────────────────────────────────
 Binary semaphore case: max_threads{10U}, max_sema_threads{1}

 Threads: 10, Throughput: 1 │ Legend: initial delay ░░ │ wait state ▒▒ │ sema occupation ██

 # 6 ░░░░████
 # 5 ░░░░▒▒▒▒████
 # 4 ░░░░░░░░░░▒▒██████████
 # 7 ░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒████████████████
 # 2 ░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██████
 # 3 ░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████████
 # 0 ░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████████
 # 1 ░░░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒████████
 # 8 ░░░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██████
 # 9 ░░░░░░░░░░░░░░░░░░▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒▒██████████████

.SH See also

   release           increments the internal counter and unblocks acquirers
                     \fI(public member function)\fP
   try_acquire       tries to decrement the internal counter without blocking
                     \fI(public member function)\fP
                     tries to decrement the internal counter, blocking for up to a
   try_acquire_for   duration time
                     \fI(public member function)\fP
                     tries to decrement the internal counter, blocking until a point in
   try_acquire_until time
                     \fI(public member function)\fP
